package org.origin.centre.support.utils;

import java.lang.reflect.Method;
import java.util.*;

/**
 * Tree 工具类
 *
 * @author ferret
 * @version 2024-05-08
 */
@SuppressWarnings("unused")
public final class TreeUtil {

    /**
     * 获取树结构数据
     *
     * @param list 数据源
     * @return 树结构数据
     */
    public static <T> List<T> getTree(List<T> list) {
        return getTree(list, "", new GeneralConvert<>(), new GeneralParser<>());
    }

    /**
     * 获取树结构数据
     *
     * @param list   数据源
     * @param rootId 顶级ID
     * @return 树结构数据
     */
    public static <T> List<T> getTree(List<T> list, String rootId) {
        return getTree(list, rootId, new GeneralConvert<>(), new GeneralParser<>());
    }

    /**
     * 获取树结构数据
     *
     * @param list    数据源
     * @param convert Convert
     * @return 树结构数据
     */
    public static <T, R> List<R> getTree(List<T> list, Convert<T, R> convert) {
        return getTree(list, "", convert, new GeneralParser<>());
    }

    /**
     * 获取树结构数据
     *
     * @param list    数据源
     * @param rootId  顶级
     * @param convert Convert
     * @return 树结构数据
     */
    public static <T, R> List<R> getTree(List<T> list, String rootId, Convert<T, R> convert) {
        return getTree(list, rootId, convert, new GeneralParser<>());
    }

    /**
     * 获取树结构数据
     *
     * @param list   数据源
     * @param parser Parser
     * @return 树结构数据
     */
    public static <T> List<T> getTree(List<T> list, Parser<T, T> parser) {
        return getTree(list, "", new GeneralConvert<>(), parser);
    }

    /**
     * 获取树结构数据
     *
     * @param list   数据源
     * @param rootId 顶级
     * @param parser Parser
     * @return 树结构数据
     */
    public static <T> List<T> getTree(List<T> list, String rootId, Parser<T, T> parser) {
        return getTree(list, rootId, new GeneralConvert<>(), parser);
    }

    /**
     * 获取树结构数据
     *
     * @param list        数据源
     * @param getId       GetId <方便 lambda 表达式>
     * @param getParentId GetParentId <方便 lambda 表达式>
     * @param getChildren GetChildren <方便 lambda 表达式>
     * @param setChildren SetChildren <方便 lambda 表达式>
     * @return 树结构数据
     */
    public static <T> List<T> getTree(List<T> list, GetId<T> getId, GetParentId<T> getParentId, GetChildren<T> getChildren, SetChildren<T, T> setChildren) {
        return getTree(list, "", new GeneralConvert<>(), getId, getParentId, getChildren, setChildren);
    }

    /**
     * 获取树结构数据
     *
     * @param list        数据源
     * @param getId       GetId <方便 lambda 表达式>
     * @param getParentId GetParentId <方便 lambda 表达式>
     * @param getChildren GetChildren <方便 lambda 表达式>
     * @param setChildren SetChildren <方便 lambda 表达式>
     * @return 树结构数据
     */
    public static <T> List<T> getTree(List<T> list, String rootId, GetId<T> getId, GetParentId<T> getParentId, GetChildren<T> getChildren, SetChildren<T, T> setChildren) {
        return getTree(list, rootId, new GeneralConvert<>(), getId, getParentId, getChildren, setChildren);
    }

    /**
     * 获取树结构数据
     *
     * @param list    数据源
     * @param convert Convert
     * @param parser  Parser
     * @return 树结构数据
     */
    public static <T, R> List<R> getTree(List<T> list, Convert<T, R> convert, Parser<T, R> parser) {
        return getTree(list, "", convert, parser);
    }

    /**
     * 获取树结构数据
     *
     * @param list    数据源
     * @param convert Convert
     * @param parser  Parser
     * @return 树结构数据
     */
    public static <T, R> List<R> getTree(List<T> list, String rootId, Convert<T, R> convert, Parser<T, R> parser) {
        return getTree(list, rootId, convert, parser, parser, parser, parser);
    }

    /**
     * 获取树结构数据
     *
     * @param list        数据源
     * @param convert     Convert <方便 lambda 表达式>
     * @param getId       GetId <方便 lambda 表达式>
     * @param getParentId GetParentId <方便 lambda 表达式>
     * @param getChildren GetChildren <方便 lambda 表达式>
     * @param setChildren SetChildren <方便 lambda 表达式>
     * @return 树结构数据
     */
    public static <T, R> List<R> getTree(List<T> list, Convert<T, R> convert, GetId<T> getId, GetParentId<T> getParentId, GetChildren<R> getChildren, SetChildren<T, R> setChildren) {
        return getTree(list, "", convert, getId, getParentId, getChildren, setChildren);
    }

    /**
     * 获取树结构数据
     *
     * @param list        数据源
     * @param rootId      顶级ID
     * @param convert     Convert <方便 lambda 表达式>
     * @param getId       GetId <方便 lambda 表达式>
     * @param getParentId GetParentId <方便 lambda 表达式>
     * @param getChildren GetChildren <方便 lambda 表达式>
     * @param setChildren SetChildren <方便 lambda 表达式>
     * @return 树结构数据
     */
    public static <T, R> List<R> getTree(List<T> list, String rootId, Convert<T, R> convert, GetId<T> getId, GetParentId<T> getParentId, GetChildren<R> getChildren, SetChildren<T, R> setChildren) {
        if (list != null && list.size() > 0) {
            boolean hasRootId = isNotBlank(rootId);
            List<R> tree = new ArrayList<>();
            Map<String, R> cacheMap = new HashMap<>();
            for (T item : list) {
                if (item != null) {
                    R data = convert.convert(item);
                    String id = getString(getId.getId(item));
                    if (isNotBlank(id)) {
                        cacheMap.put(id.trim(), data);
                    }
                }
            }
            for (T item : list) {
                boolean isRoot;
                if (item != null) {
                    String id = getString(getId.getId(item));
                    String parentId = getString(getParentId.getParentId(item));
                    if (isNotBlank(parentId)) {
                        if (hasRootId) {
                            isRoot = parentId.equals(rootId);
                        } else {
                            isRoot = !cacheMap.containsKey(parentId);
                        }
                    } else {
                        isRoot = true;
                    }
                    R data = cacheMap.get(id);
                    if (isRoot) {
                        if (data != null) {
                            tree.add(data);
                        }
                    } else {
                        R parent = cacheMap.get(parentId);
                        if (parent != null) {
                            List<R> children = getChildren.getChildren(parent);
                            if (data != null) {
                                if (children == null) children = new ArrayList<>();
                                children.add(data);
                            }
                            setChildren.setChildren(parent, children);
                        }
                    }
                }
            }
            cacheMap.clear();
            return tree;
        }
        return null;
    }

    /**
     * 将树结构数据打开
     *
     * @param list        数据源
     * @param getChildren GetChildren <方便 lambda 表达式>
     * @return 树结构数据
     */
    public static <T> List<T> getList(List<T> list, GetChildren<T> getChildren) {
        return getList(list, e -> e, getChildren);
    }

    /**
     * 将树结构数据打开
     *
     * @param <T> 源列表中的元素类型
     * @param <R> 转换后的目标元素类型
     * @param list 源列表
     * @param convert 转换器，用于将源元素转换为目标元素
     * @param getChildren 子元素获取器，用于获取源元素的子元素
     * @return 树结构数据
     */
    public static <T, R> List<R> getList(List<T> list, Convert<T, R> convert, GetChildren<T> getChildren) {
        if (list != null && list.size() > 0) {
            int number = 1000000; // 递归层数限制
            List<R> result = new ArrayList<>();
            Stack<List<T>> stack = new Stack<>();
            stack.push(list);
            if (!stack.empty()) {
                List<T> cList = stack.pop();
                if (cList != null && cList.size() > 0) {
                    for (T item : cList) {
                        number--;
                        if (item != null) {
                            R newItem = convert.convert(item);
                            if (newItem != null) {
                                result.add(newItem);
                                List<T> children = getChildren.getChildren(item);
                                if (children != null && children.size() > 0) {
                                    stack.push(children);
                                }
                            }
                        }
                    }
                }
                if (number < 0) throw new IllegalArgumentException("递归层级太深！");
            }
            return result;
        }
        return null;
    }

    /**
     * 将树结构数据打开
     *
     * @param list        数据源
     * @param convert     Convert <方便 lambda 表达式>
     * @param getChildren GetChildren <方便 lambda 表达式>
     * @return 树结构数据
     */
    @SuppressWarnings("unchecked")
    public static <T, R> List<R> getList(List<T> list, GetChildren<T> getChildren, ConvertList<T, R> convert) {
        if (list != null && list.size() > 0) {
            int number = 1000000;
            List<R> result = new ArrayList<>();
            Stack<Object[]> stack = new Stack<>();
            stack.push(new Object[]{null, list});
            if (!stack.empty()) {
                Object[] objects = stack.pop();
                if (objects != null && objects.length == 2) {
                    Object _cParent = objects[0];
                    Object _cList = objects[1];
                    R cParent = _cParent != null ? (R) _cParent : null;
                    List<T> cList = _cList != null ? (List<T>) _cList : null;
                    if (cList != null && cList.size() > 0) {
                        for (T item : cList) {
                            number--;
                            if (item != null) {
                                R newItem = convert.convert(cParent, item);
                                if (newItem != null) {
                                    result.add(newItem);
                                    List<T> children = getChildren.getChildren(item);
                                    if (children != null && children.size() > 0) {
                                        stack.push(new Object[]{newItem, children});
                                    }
                                }
                            }
                        }
                    }
                }
                if (number < 0) throw new IllegalArgumentException("递归层级太深！");
            }
            return result;
        }
        return null;
    }

    /**
     * 获取数据的属性名对应的值或Map的key对应的值
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> getList(T data, String name) {
        Object value = getValue(data, name);
        return value != null ? (List<T>) value : null;
    }

    /**
     * 设置默认children
     */
    public static <T, R> void setChildren(R parent, List<R> children, R data, T item) {
        setValue(parent, "children", children);
    }

    /**
     * 获取对象或者Map中的属性值
     *
     * @param target Object
     * @param name   属性名称
     * @return 属性值
     */
    public static Object getValue(Object target, String name) {
        if (target != null && isNotBlank(name)) {
            if (target instanceof Map<?, ?> map) {
                return map.get(name);
            } else {
                try {
                    Class<?> clazz = target.getClass();
                    String getMethodName = "get" + upperFirst(name);
                    Method method = clazz.getDeclaredMethod(getMethodName);
                    return method.invoke(target);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 设置对象或者Map中的属性值
     *
     * @param target Object
     * @param name   属性名称
     * @param data   属性的值
     */
    @SuppressWarnings("unchecked")
    public static void setValue(Object target, String name, Object data) {
        if (target != null && isNotBlank(name)) {
            if (target instanceof Map) {
                Map<String, Object> map = (Map<String, Object>) target;
                map.put(name, data);
            } else {
                try {
                    Class<?> clazz = target.getClass();
                    String attr = upperFirst(name);
                    String setMethodName = "set" + attr;
                    String getMethodName = "get" + attr;
                    Method getMethod = clazz.getDeclaredMethod(getMethodName);
                    Method setMethod = clazz.getDeclaredMethod(setMethodName, getMethod.getReturnType());
                    setMethod.invoke(target, data);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 获取String对象
     */
    public static String getString(Object object) {
        return object != null ? object.toString() : null;
    }

    /**
     * 将字符串的首字母变为大写
     *
     * @param str 字符串
     * @return 首字母大写字符串
     */
    public static String upperFirst(String str) {
        if (str != null) {
            char[] chars = str.toCharArray();
            chars[0] = Character.toUpperCase(chars[0]);
            return String.valueOf(chars);
        }
        return null;
    }

    /**
     * 判断是否不为空
     *
     * @param str 参数
     * @return 是否为空
     */
    public static boolean isNotBlank(String str) {
        return !isBlank(str);
    }

    /**
     * 判断是否为空
     *
     * @param str 参数
     * @return 是否为空
     */
    public static boolean isBlank(String str) {
        return str == null || str.trim().length() <= 0;
    }

    public interface Convert<T, R> {
        R convert(T data);
    }

    public interface GetId<T> {
        Object getId(T data);
    }

    public interface GetParentId<T> {
        Object getParentId(T data);
    }

    public interface GetChildren<T> {
        List<T> getChildren(T parent);
    }

    public interface SetChildren<T, R> {
        void setChildren(R parent, List<R> children);
    }

    public interface ConvertList<T, R> {
        R convert(R parent, T data);
    }

    public interface Parser<T, R> extends GetId<T>, GetParentId<T>, GetChildren<R>, SetChildren<T, R> {

    }

    public static class GeneralParser<T, R> implements Parser<T, R> {
        protected String idKey = "id";
        protected String parentIdKey = "parentId";
        protected String childrenKey = "children";

        public GeneralParser() {
        }

        public GeneralParser(String idKey, String parentIdKey, String childrenKey) {
            this.idKey = idKey;
            this.parentIdKey = parentIdKey;
            this.childrenKey = childrenKey;
        }

        public GeneralParser<T, R> setIdKey(String idKey) {
            this.idKey = idKey;
            return this;
        }

        public GeneralParser<T, R> setParentIdKey(String parentIdKey) {
            this.parentIdKey = parentIdKey;
            return this;
        }

        public GeneralParser<T, R> setChildrenKey(String childrenKey) {
            this.childrenKey = childrenKey;
            return this;
        }

        @Override
        public Object getId(T data) {
            return getValue(data, this.idKey);
        }

        @Override
        public Object getParentId(T data) {
            return getValue(data, this.parentIdKey);
        }

        @Override
        public List<R> getChildren(R parent) {
            return getList(parent, this.childrenKey);
        }

        @Override
        public void setChildren(R parent, List<R> children) {
            setValue(parent, this.childrenKey, children);
        }
    }

    public static class GeneralConvert<T> implements Convert<T, T> {

        @Override
        public T convert(T data) {
            return data;
        }
    }

}
